package com.zorzhi.automation.utils;

import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.zorzhi.automation.entity.MergeEntity;
import com.zorzhi.automation.entity.R;

import java.io.*;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * @Author zorzhi
 * @Date 2025/4/21 19:30
 */
public class MergeUtil {

    private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd");

    /**
     * 动态获取 Maven 可执行文件路径的方法
     * @return  maven可执行文件路径
     */
    public static String getMavenExecutablePath() {
        // 尝试从 MAVEN_HOME 环境变量中获取 Maven 路径
        String mavenHome = System.getenv("MAVEN_HOME");
        if (mavenHome != null && !mavenHome.isEmpty()) {
            return mavenHome + "\\bin\\mvn.cmd";
        }

        // 尝试从 PATH 环境变量中查找 mvn 命令
        try {
            // 根据操作系统选择合适的文件名和路径分隔符
            String mvnFileName = isWindows() ? "mvn.cmd" : "mvn";
            String pathSeparator = File.pathSeparator;
            String pathEnv = System.getenv("PATH");

            File mavenExecutable = null;
            for (String p : pathEnv.split(pathSeparator)) {
                File dir = new File(p);
                if (dir.exists() && dir.isDirectory()) {
                    File candidate = new File(dir, mvnFileName);
                    if (candidate.exists() && candidate.canExecute()) {
                        mavenExecutable = candidate;
                        break;
                    }
                }
            }

            if (mavenExecutable != null) {
//                ProcessBuilder pb = new ProcessBuilder(mavenExecutable.getAbsolutePath(), "-v");
//                pb.inheritIO(); // 继承标准输入输出，便于调试
//                Process process = pb.start();

                Process process = Runtime.getRuntime().exec(new String[]{mavenExecutable.getAbsolutePath(), "-v"});

                // 输出结果
                BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
                String line;
                while ((line = reader.readLine()) != null) {
                    if (line.contains("Maven home")) {
                        line = line.replace("Maven home:", "").replace("..",mvnFileName);
                        System.err.println("Maven Path: " + line);
                        break;
                    }
                }

                int exitCode = process.waitFor();
                System.out.println("Exit code: " + exitCode);
                return line;
            } else {
                System.out.println("Maven executable not found in PATH.");
            }

        } catch (Exception e) {
            e.printStackTrace();
        }

        // 如果仍未找到，返回 null
        return null;
    }


    /**
     * 动态获取 npm 可执行文件路径的方法
     * @return  npm可执行文件路径
     */
    public static String getNpmExecutablePath() {
        // 根据操作系统选择合适的文件名和路径分隔符
        String npmFileName = isWindows() ? "npm.cmd" : "npm";
        String pathSeparator = File.pathSeparator;
        String pathEnv = System.getenv("PATH");

        if (pathEnv != null && !pathEnv.isEmpty()) {
            String[] paths = pathEnv.split(pathSeparator);
            for (String path : paths) {
                File npmCmd = new File(path, npmFileName);
                if (npmCmd.exists() && npmCmd.canExecute()) {
                    String  npmPath = npmCmd.getAbsolutePath();
                    System.err.println("Npm Path: " + npmPath);
                    return npmPath;
                }
            }
        }

        // 如果仍未找到，返回 null
        return null;
    }

    public static boolean isWindows() {
        String osName = System.getProperty("os.name").toLowerCase();
        return osName.contains("win");
    }

    /**
     * 删除目录及其子文件
     * @param directory 要删除的目录
     */
    public static void deleteDirectory(File directory) {
        if (directory.exists()) {
            File[] files = directory.listFiles();
            if (files != null) {
                for (File file : files) {
                    if (file.isDirectory()) {
                        deleteDirectory(file);
                    } else {
                        file.delete();
                    }
                }
            }
            directory.delete();
        }
    }

    /**
     * 复制目录 到 指定目录下
     * @param source    源目录
     * @param target    目标目录
     * @throws IOException
     */
    public static void copyDirectoryRecursively(Path source, Path target) throws IOException {
        // 创建目标目录
        Files.createDirectories(target);

        // 使用Files.walkFileTree遍历源目录
        Files.walkFileTree(source, new SimpleFileVisitor<Path>() {
            @Override
            public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
                // 构造相对路径并确定在目标位置创建的目录路径
                Path newDir = target.resolve(source.relativize(dir));
                // 如果目标目录不存在，则创建它
                if (!Files.exists(newDir)) {
                    Files.createDirectory(newDir);
                }
                return FileVisitResult.CONTINUE;
            }

            @Override
            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                // 复制文件到目标位置
                Files.copy(file, target.resolve(source.relativize(file)), StandardCopyOption.REPLACE_EXISTING);
                return FileVisitResult.CONTINUE;
            }
        });
    }

    /**
     * 创建 分支名称对应的 当时时间 文件夹
     * @param deploymentPackagePath 部署包路径
     * @param branchName    分支名称
     * @return  创建后文件夹路径
     */
    public static String createBranchDirectory(String deploymentPackagePath, String branchName) {
        File folder = new File(deploymentPackagePath, branchName);
        if (!folder.exists()) {
            folder.mkdirs();
        }

        // 【7】、创建子文件夹，名称为当前时间
        String timestamp = new SimpleDateFormat("yyyy-MM-dd_HHmmss").format(new Date());
        File timestampFolder = new File(folder, timestamp);
        if (!timestampFolder.exists()) {
            timestampFolder.mkdirs();
        }
        return timestampFolder.getPath();
    }


    /**
     * 将int类型的秒时间戳转换为日期时间字符串
     * @param timestampInMillis 秒的时间戳
     */
    public static String IntTimestampToDate(long timestampInMillis){
        // 转换为毫秒（关键步骤！）
        Instant instant = Instant.ofEpochMilli(timestampInMillis * 1000);

        // 使用北京时间（可替换为你需要的时区）
        ZoneId zone = ZoneId.of("Asia/Shanghai");

        // 转换为当地时间
        LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, zone);

        // 格式化输出
        String result = localDateTime.format(formatter);
        return result;
    }




    public static void main(String[] args) throws Exception {
        String givenDateString = "20240924";
        String sqlPath = "D:\\WorkSpace\\Project\\smartCampus_marge\\Campus\\src\\main\\java\\sql\\update";
        String sqlTargetPath = "C:\\Users\\zorzhi\\Desktop\\TEST\\zor_dev\\sql";
        findAndCopySqlFiles(givenDateString, sqlPath, sqlTargetPath);
    }


    /**
     * 获取给定日期之后的所有SQL文件
     * @param givenDateString   给定日期
     * @param sourceDirPath     文件所在路径
     * @param targetDirPath     文件所在路径
     */
    public static List<Path> findAndCopySqlFiles(String givenDateString, String sourceDirPath, String targetDirPath) throws Exception {
        Pattern FILE_PATTERN = Pattern.compile("^(\\d{8})(?:[^.]*)?\\.sql$", Pattern.CASE_INSENSITIVE);
        LocalDate givenDate = LocalDate.parse(givenDateString, formatter);
        Path sourceDir = Paths.get(sourceDirPath);
        Path targetDir = Paths.get(targetDirPath);

        // 创建目标目录（如果不存在）
        if (!Files.exists(targetDir)) {
            Files.createDirectories(targetDir);
        }

        List<Path> matchedFiles = new ArrayList<>();
        Path mergedFilePath = targetDir.resolve("总更新语句.sql");
        // 遍历 update 下的所有子目录
        try (DirectoryStream<Path> dirStream = Files.newDirectoryStream(sourceDir);
            BufferedWriter writer = Files.newBufferedWriter(mergedFilePath)) {

            for (Path yearDir : dirStream) {
                if (Files.isDirectory(yearDir) && isYearFolder(yearDir.getFileName().toString())) {
                    System.out.println("正在处理年份目录: " + yearDir);

                    // 遍历该年份目录下所有 .sql 文件
                    Files.walkFileTree(yearDir, new SimpleFileVisitor<Path>() {
                        @Override
                        public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                            String fileName = file.getFileName().toString();
                            Matcher matcher = FILE_PATTERN.matcher(fileName);

                            if (matcher.matches()) {
                                String dateStr = matcher.group(1);
                                try {
                                    LocalDate fileDate = LocalDate.parse(dateStr, formatter);

                                    if (!fileDate.isBefore(givenDate)) {
                                        System.out.println("匹配成功: " + fileName);
                                        matchedFiles.add(file);

                                        // 复制文件到目标目录（重名会覆盖）
                                        Path destFile = targetDir.resolve(fileName);
                                        Files.copy(file, destFile, StandardCopyOption.REPLACE_EXISTING);

                                        // 将 sql语句添加到总更新语句文件中
                                        Files.readAllLines(file).forEach(line -> {
                                            try {
                                                writer.write(line);
                                                writer.newLine(); // 添加换行符以保持原始格式
                                            } catch (IOException e) {
                                                e.printStackTrace();
                                            }
                                        });
                                        writer.write("\n-- --------------------------------------------------------\n");
                                        writer.newLine();
                                    }
                                } catch (Exception e) {
                                    System.err.println("无法解析日期: " + fileName);
                                }
                            } else {
                                System.out.println("未匹配文件名格式: " + fileName);
                            }
                            return FileVisitResult.CONTINUE;
                        }
                    });
                }
            }
        }

        System.out.println("共找到符合条件的SQL文件数量: " + matchedFiles.size());
        return matchedFiles;
    }

    // 判断是否为年份文件夹（四位数字）
    private static boolean isYearFolder(String folderName) {
        return folderName != null && folderName.matches("\\d{4}");
    }



    private static final String[] FOLDERS_TO_COMPRESS = {"api", "dist", "web"};

    /**
     * 压缩指定目录下的特定文件夹，并在压缩成功后删除这些文件夹。
     *
     * @param directoryPath 目标目录路径
     * @throws IOException 抛出IO异常
     */
    public static boolean compressFolders(String directoryPath) throws IOException {
        Path dirPath = Paths.get(directoryPath);
        if (!Files.exists(dirPath) || !Files.isDirectory(dirPath)) {
            throw new IllegalArgumentException("目录不存在或不是一个目录");
        }

        // 获取目录名作为压缩包的一部分名称
        String folderName = dirPath.getFileName().toString();
        String zipFileName = directoryPath + File.separator + "update_" + folderName + ".zip";

        // 创建输出流写入到ZIP文件
        try (FileOutputStream fos = new FileOutputStream(zipFileName);
             ZipOutputStream zos = new ZipOutputStream(fos)) {

            for (String folderNameToCompress : FOLDERS_TO_COMPRESS) {
                Path folderPath = dirPath.resolve(folderNameToCompress);
                if (Files.exists(folderPath) && Files.isDirectory(folderPath)) {
                    // 压缩当前文件夹，并传入统一的根目录结构
                    compressDirectory(folderPath, dirPath, zos);
                }
            }
        }
        System.out.println("压缩完成: " + zipFileName);
        return true;
    }

    /**
     * 递归压缩指定文件夹及其所有子文件。
     *
     * @param folderToCompress 需要压缩的文件夹路径
     * @param rootDir          整体根目录（用于计算相对于整个 ZIP 归档的路径）
     * @param zos              ZIP 输出流
     * @throws IOException     抛出 IO 异常
     */
    private static void compressDirectory(Path folderToCompress, Path rootDir, ZipOutputStream zos) throws IOException {
        Files.walkFileTree(folderToCompress, new SimpleFileVisitor<Path>() {
            @Override
            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                // 获取当前文件相对于根目录的路径作为 ZIP 中的路径
                String zipEntryName = rootDir.relativize(file).toString().replace("\\", "/");
//                System.out.println("Adding to zip: " + zipEntryName);

                zos.putNextEntry(new ZipEntry(zipEntryName));
                try (InputStream is = Files.newInputStream(file)) {
                    byte[] buffer = new byte[1024];
                    int len;
                    while ((len = is.read(buffer)) > 0) {
                        zos.write(buffer, 0, len);
                    }
                }
                zos.closeEntry();
                return FileVisitResult.CONTINUE;
            }

            @Override
            public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
                if (dir.equals(folderToCompress)) {
                    return FileVisitResult.CONTINUE; // 跳过根目录本身
                }

                String zipEntryName = rootDir.relativize(dir).toString().replace("\\", "/");
                if (!zipEntryName.isEmpty()) {
                    zos.putNextEntry(new ZipEntry(zipEntryName + "/"));
                    zos.closeEntry();
                }
                return FileVisitResult.CONTINUE;
            }
        });
    }

    /**
     * 获取合并配置文件内容
     */
    public static R getMergeFileContent() {
        String content = null;
        try {
            // 获取当前项目的工作目录（即启动时的目录）
            File currentDir = new File("").getAbsoluteFile();
            File file = new File(currentDir, "autoMerge.txt");

            if (file.exists()) {
                // 文件存在，读取内容
                content = new String(Files.readAllBytes(file.toPath()));
                System.out.println("读取到文件内容: " + content);

            } else {
                // 文件不存在，创建并写入默认内容
                boolean created = file.createNewFile();
                if (!created) {
                    return R.failure("autoMerge文件创建失败");
                }

                // 写入默认内容（可根据需要自定义）
                JSONObject jsonObject = new JSONObject();
                jsonObject.putOnce("deploymentPath", "C:\\Users\\zorzhi\\Desktop\\TEST")
                        .putOnce("projectPath", "D:\\WorkSpace\\Project\\smartCampus_marge")
                        .putOnce("pcProjectName", "Campus")
                        .putOnce("vueProjectName", "Campus-ui")
                        .putOnce("uniAppProjectName", "Campus-app")
                        .putOnce("gitAccount", "zorzhi")
                        .putOnce("gitPassword", "")
                        .putOnce("gitUrl", "https://gitee.com/Quasdomo/smart-campus.git");
                content = jsonObject.toString();
                Files.write(file.toPath(), content.getBytes());

                System.out.println("autoMerge文件已写入内容\n" + content);
            }
        } catch (IOException e) {
            e.printStackTrace();
            return R.failure("文件操作失败：" + e.getMessage());
        }

        MergeEntity mergeEntity = JSONUtil.toBean(content, MergeEntity.class);
        String gitPassword = mergeEntity.getGitPassword();
        if (gitPassword.length() > 6) {
            gitPassword = gitPassword.substring(3, gitPassword.length() - 3);
            mergeEntity.setGitPassword(gitPassword);
        }

        return R.success(mergeEntity);
    }

    /**
     * 获取密钥
     */
    public static String getMergeFilePassword() {
        R mergeFileContent = getMergeFileContent();
        if (mergeFileContent.getCode() != 200) {
            return null;
        }
        MergeEntity mergeEntity = (MergeEntity)mergeFileContent.getData();
        return mergeEntity.getGitPassword();
    }
}
